3D 游戏开发

3D 游戏开发

3D 项目设置

# 项目设置 -> Rendering -> Lighting and Shadows
# Directional Light Shadows: PCF16 (for better shadows)

# 项目设置 -> Rendering -> Environment
# Default Clear Color

3D 节点层次

WorldEnvironment
├── DirectionalLight3D
├── Camera3D
├── Player
│   ├── MeshInstance3D
│   ├── CollisionShape3D
│   └── ...
└── Level
    ├── StaticBody3D
    │   ├── MeshInstance3D
    │   └── CollisionShape3D
    └── ...

角色移动

3D 角色移动

extends CharacterBody3D

@export var speed: float = 5.0
@export var sprint_multiplier: float = 1.5

func _physics_process(delta: float) -> void:
    var input_dir = Input.get_vector("move_left", "move_right", "move_forward", "move_back")
    var direction = (transform.basis * Vector3(input_dir.x, 0, input_dir.y)).normalized()

    if direction != Vector3.ZERO:
        velocity.x = direction.x * speed
        velocity.z = direction.z * speed
    else:
        velocity.x = move_toward(velocity.x, 0, speed)
        velocity.z = move_toward(velocity.z, 0, speed)

    move_and_slide()

3D 相机跟随

extends Camera3D

@export var target: Node3D
@export var offset: Vector3 = Vector3(0, 5, 10)
@export var smooth_speed: float = 10.0

func _process(delta: float) -> void:
    if target:
        var target_pos = target.global_position + offset
        global_position = lerp(global_position, target_pos, smooth_speed * delta)
        look_at(target.global_position)

3D 物理

RigidBody3D

extends RigidBody3D

@export var force: float = 100.0

func _integrate_forces(state: PhysicsDirectBodyState3D) -> void:
    if Input.is_action_pressed("ui_up"):
        apply_central_force(Vector3.FORWARD * force)

StaticBody3D

用于静态物体,不会移动但有碰撞。

Area3D

用于检测区域,无碰撞但可以检测。

extends Area3D

signal player_entered

func _on_body_entered(body: Node3D) -> void:
    if body.is_in_group("player"):
        player_entered.emit()

3D 渲染

MeshInstance3D

# 更改网格
mesh = preload("res://models/player.glb")

# 更改材质
set_surface_override_material(0, preload("res://materials/player_material.tres"))

创建简单形状

extends MeshInstance3D

func _ready() -> void:
    # 立方体
    mesh = BoxMesh.new()

    # 球体
    mesh = SphereMesh.new()

    # 圆柱体
    mesh = CylinderMesh.new()

光照

DirectionalLight3D (方向光)

模拟太阳光,平行光线。

@export_range(0, 1) var shadow_intensity: float = 0.5

func _ready() -> void:
    shadow_enabled = true
    light_energy = 1.0

OmniLight3D (点光源)

向四面八方发光。

extends OmniLight3D

func _ready() -> void:
    omni_range = 20.0
    omni_attenuation = 2.0

SpotLight3D (聚光灯)

锥形光照。

extends SpotLight3D

func _ready() -> void:
    spot_range = 30.0
    spot_angle = 45.0

环境

WorldEnvironment

extends WorldEnvironment

func _ready() -> void:
    environment.ambient_light_source = Environment.AMBIENT_SOURCE_SKY
    environment.ambient_light_color = Color(0.5, 0.5, 0.5)

Sky

# 使用程序化天空
var sky = Sky.new()
var sky_material = ProceduralSkyMaterial.new()
sky.sky_material = sky_material
environment.sky = sky

3D 动画

AnimationTree

extends AnimationTree

func _process(delta: float) -> void:
    var input_vector = Input.get_vector("move_left", "move_right", "move_forward", "move_back")
    parameters["move_speed"] = input_vector.length()

地形

GridMap

extends GridMap

func _ready() -> void:
    # 设置网格大小
    cell_size = Vector3(2, 2, 2)

    # 放置单元格
    set_cell_item(Vector3i(0, 0, 0), 0, 0)

3D 射线检测

extends Node3D

@onready var camera = $Camera3D

func _input(event: InputEvent) -> void:
    if event is InputEventMouseButton and event.pressed:
        var ray_origin = camera.project_ray_origin(event.position)
        var ray_direction = camera.project_ray_normal(event.position)
        var ray_param = PhysicsRayQueryParameters3D.create(ray_origin, ray_origin + ray_direction * 1000)
        var result = get_world_3d().direct_space_state.intersect_ray(ray_param)

        if result:
            print("Hit: ", result.collider.name)

3D 坐标系统

性能优化建议

  1. 合并静态网格
  2. 使用 LOD (Level of Detail)
  3. 减少动态光源
  4. 使用遮挡剔除
  5. 优化碰撞形状